package fifteenth;

// Java反射机制
public class Note {
}
/**
 * Java中重要的就是Java的反射机制，那么什么是反射机制呢？
 * 比如：正常的情况下如果已经有一个类了，则肯定可以通过类创建对象；那么如果现在要求可以通过一个对象找到一个类的名称，此时就需要反射机制。
 * 如果想要完成反射机制，首先应该认识的就是Class类。
 * 在反射操作中，一定要把握一个核心概念：一切的操作都将使用Object完成，类、数组的引用都可以使用Objecct进行接收。
 * <p>
 * 提示：所有的类实际上也都是Class类的实例
 * Java中Object类是一切类的父类，那么所有类的对象实际上也就是java.lang.Class类的实例
 * 所有的对象都可以转变成java.lang.Class类型表示
 * Class类常用方法：
 * public static Class<?> forName(String className)：传入完整的”包.类“名称，实例化Class对象
 * public Constructor[] getConstructors():得到一个类中的全部构造方法
 * public Field[] getDeclaredFields()：得到一个类中的全部构造方法
 * public Field[] getFields():取得本类的全部属性
 * public Methods[] getMethods()：得到一个类中的全部方法
 * public Method getMethod(String name,Class... paramtersTypes)：返回一个Method对象，并设置一个方法中的所有参数类型
 * public Class[] getInterfaces()：得到一个类中所实现的全部接口
 * public String getName()：得到一个类完整的“包.类"名称
 * public Package getPackage()：得到一个类的包
 * public Class getSuperclass()：得到一个类的父类
 * public Object newInstance()：根据Class定义的类实例化对象
 * public Class<?> getComponentType():返回表示数组类型的Class
 * public boolean isArray():判断此Class是否是一个数组
 * 在Class中没有任何的构造方法，所以如果要使用必须首先通过forName()的静态方法实例化对象
 * 除此之外，也可以用”类.class"或“对象.getClass()"方法实例化。
 * <p>
 * Class在实际中，最常用的就是实例化对象的操作，即可以通过一个给定的字符串（这个字符串包含了完整的包.类的路径）来实例化一个类的对象
 * <p>
 * 提示：各种高级应用中都提倡类中存在无参构造方法
 * 在Java中，反射是最重要的操作原理，在现在的开发设计中大量地应用了反射处理机制，如Structs，Spring框架；
 * 大部分都是操作无参构造方法，所以希望读者在以后使用反射开发代码的时候 一定要保留无参构造方法
 *
 * 当然，对于以上的程序也并非没有解决方法，可以通过其他的方式进行实例化操作，只是在操作的时候需要明确的调用类中的构造方法，
 * 并将参数传递进去之后才可以进行实例化操作，操作步骤如下：
 * ①通过Class类中的getConstructors()取得本类中的所有构造方法
 * ②向构造方法中传递一个对象数组，里面包含了构造方法的参数
 * ③之后通过Constructor实例化对象
 * Constructor类，表示的是构造方法。
 * 常用方法：
 * int getModifiers()：得到构造方法的修饰符
 * String getName():得到构造方法的名称
 * Class<?>[] getParameterTypes()：得到构造方法中参数的类型
 * String toString():返回此构造方法的信息
 * T newInstance(Object... initargs):向构造方法中传递参数，实例化对象
 *
 * 反射的应用----取得类的结构
 * 可以通过反射得到一个类的完整结构，这就要用到java.lang.reflect包中的以下功能：
 * ①Constructor：表示类中的构造方法
 * ②Field：表示类中的属性
 * ③Method：表示类中的方法
 * 这三个类都是AccessibleObject类的子类
 *
 *  取得全部属性
 *  在反射操作中，同样也可以取得一个类中的全部属性，但是在取得属性的时候有以下两种不同的操作。
 *  ①得到实现的接口或父类中的公共属性：public Field[] getFields() throws SecurityException
 *  ②得到本类中的全部属性:public Field[] getDeclaredFields() throws SecurityException
 *  以上方法返回的都是Field的数组，每一个Field对象就表示类中的一个属性，要想取得属性的进一步信息，就需要使用下面1的方法：
 *  Object get(Object obj):得到一个对象中属性的具体内容
 *  set(Object obj,Object value)：设置指定对象中属性的具体内容
 *  int getModifiers()：得到属性的修饰符
 *  String getName()：返回此属性的名称
 *  boolean isAccessible():判断此属性是否可呗外部访问
 *  setAccessible(boolean flag):设置一个属性是否可以被外部访问
 *  setAccessible(AccessibleObject[] array,boolean  flag)：将一组属性设置是否可被外部访问
 *  String toString()；返回此Field类的信息
 *
 *  Java反射机制的深入应用
 *  反射除了可以取得一个类的结构外，还可以调用类中的指定方法或指定属性，并且可以通过反射完成对数组的操作
 *
 *  通过反射调用类中的方法
 *  如果要使用反射调用类中的方法 可以通过Method类完成，操作步骤：
 *  ①通过Class类的getMethods(String name,Class.parameterTypes)方法取得一个Method的对象
 *      并设置此方法操作时所需要的参数类型。
 *  ②之后才可以使用invoke()方法进行调用，并向方法中传递要设置的参数
 *
 *  调用setter方法及getter方法
 *  本书从面向对象部分就一直开始强调：“类中的属性必须封装，封装之后的属性要通过setter及getter方法设置取得，那么在使用反射调用方法的操作中
 *  最重要就是调用类中getter setter方法，这一点在Java开发中随处可见。
 *
 *  通过反射操作数组
 *  反射机制不仅能用在类上，还可以应用在任意的引用数据类型的数据上，当然，这本身就包含了数组，可以通过此类进行
 *  取得数组长度，取得数组内容的操作。
 *  常用方法：
 *  Object get(Object array,int index)：根据下标取得数组内容
 *  Object newInstance(Class<?> componentType,int length):根据已有的数组类型开辟新的数组对象
 *  set(Object array,int index,Object value)：修改指定位置的内容
 *
 *  ClassLoader
 *  利用Class类可以通过反射进行类结构的操作，但是Class类只能加载CLASSPATH中定义的类文件，这样很大程度上就会带来操作的局限性。
 *  为了解决这样的问题，在Java中又提供有ClassLoader类，这个类的主要功能是可以由用户自己设置类的加载路径，
 *  比如，通过文件加载或者通过网络加载。
 *  Java中有3中类加载器：
 *  ①Bootstrap ClassLoader：此加载器采用c++编写，一般开发中是看不到的
 *  ②Extension ClassLoader：用来进行扩展类的加载，一般对应的是“jre\lib\ext”目录中的类
 *  ③AppClassLoader：加载classpath指定的类，是最常用的一种加载器
 *
 *  动态代理
 *  之前说过代理机制的操作，但是之前讲解的代理设计属于静态代理，
 *  因为每一个代理类只能为一个接口服务，这样程序开发中必然会产生过多的代理，最好的做法是可以通过一个代理类完成全部的代理功能，
 *  那么此时就必须使用动态代理功能。
 *  在Java中要实现动态代理机制，则需要java.lang.reflect.InvocationHandler接口和 java.lang.reflect.Proxy类的支持
 *  InvocationHandler接口定义：
 *      public interface InvocationHandler{
 *          public Object invoke(Object proxy,Method method,Object[] args) throws Throwable
 *      }
 *   在此接口中只定义了一个invoke()方法，此方法中有3个参数，这三个参数意义分别是：
 *   ①Object Proxy:被代理的对象
 *   ②Method method:要调用的方法
 *   ③Object args[]：方法调用时所需的参数
 *   Proxy类是专门完成代理的操作类，可以通过此类为一个或多个接口动态地生成实现类。
 *   Proxy类提供的操作方法：
 *      public static Object newProxyInstance(ClassLoader loader,Class<?> [] interfaces,InvocationHandle h) throws IllegalArgumentException
 *  通过newProxyInstance()方法就饿可以动态的生成实现类，此方法中的参数意义如下：
 *  ①ClassLoader loader：类加载器
 *  ②Class<?>[] interfaces:得到全部的接口
 *  ③InvocationHandler h:得到InvocationHandler接口的子类实例
 *  如果想要完成动态代理，就要先定义一个InvocationHandler接口的子类，以完成代理的具体操作。
 *
 *  类的声明周期
 *  在一个类编译完成之后，下一步就要开始使用类，但是如果要使用一个类，肯定离不开JVM。
 *  在程序执行中JVM通过装载、链接、初始化3个步骤完成，类的装载就是通过类加载器把.class二进制文件装入JVM的方法区，
 *  并在堆区创建描述该类的java.lang.Class对象，用来封装数据。
 *  需要提醒读者的是，同一个类只会被JVM加载一次。链接就是把二进制数据组装成可以运行的状态。
 *  链接分为校验、准备和解析3个步骤。
 *  校验用来确认此二进制文件是否适合当前的JVM（版本）；
 *  准备就是为静态成员分配内存空间，并设置默认值；
 *  解析指的是转换常量池的代码引用为直接引用的过程，直到所有的符号引用都可被运行程序使用（建立完整的对应关系）。
 *  完成之后，类型可以被初始化，初始化之后类的对象就可以正常的使用，知道一个对象不再使用之后，将被垃圾回收，释放空间。
 *  当没有任何引用指向Class对象时，将结束类的生命周期。
 *
 *  工厂设计模式
 *  工厂设计模式在Java项目开发中使用最多的设计模式，但是如果只是简单的引入一个工厂类，那么会在每次增加子类的时候频繁修改工厂类，
 *  这样的开发明显不能满足实际开发的需求，所以本节将利用反射机制解决工厂模式的适配性问题。
 *
 *  将反射应用在工厂模式上
 *  工厂设计模式在实际开发中使用的非常多，之前读者已经学习过了
 *  简单的工厂设计模式，通过简单的工厂设计模式可以达到类的解耦合的目的，
 *  但是之前的工厂设计模式依然存在问题，那就是在每增加一个子类的时候都需要修改工厂类，
 *  这样肯定会麻烦。
 *  学习完反射机制之后，就可以通过反射机制来改善工厂类，让其在增加子类的时候不用做任何的修改，以达到功能的扩充。
 *
 *
 *
 *
 *
 *
 *
 *
 *
 */

